# -*- coding: utf-8 -*-
import pandas as pd
import numpy as np
from sklearn.preprocessing import MinMaxScaler

def entropy_weight(data, features):
    """熵权法计算客观权重"""
    scaler = MinMaxScaler()
    scaled = scaler.fit_transform(data[features])
    scaled = np.where(scaled == 0, 1e-8, scaled)
    
    p = scaled / np.sum(scaled, axis=0)
    entropy = -np.sum(p * np.log(p), axis=0) / np.log(len(data))
    divergence = 1 - entropy
    weights = divergence / np.sum(divergence)
    return dict(zip(features, weights))

def evaluate_yard_and_plots(excel_path):
    """综合评估系统主函数"""
    df = pd.read_excel(excel_path)
    df = df.rename(columns=lambda x: x.strip())
    
    # 院落特征工程
    yard_group = df.groupby('院落ID')
    yard_data = []
    for yard_id, group in yard_group:
        yard_data.append({
            '院落ID': yard_id,
            '院落面积': group['院落面积'].iloc[0],
            '朝向种类数': group['地块方位'].nunique(),
            '地块总数': len(group)
        })
    yard_df = pd.DataFrame(yard_data)

    # 地块特征工程
    orientation_map = {'南':1.0, '北':0.9, '东':0.7, '西':0.6}
    df['朝向得分'] = df['地块方位'].map(orientation_map).fillna(0)

    # 计算权重
    yard_weights = entropy_weight(yard_df, ['院落面积', '朝向种类数'])
    plot_weights = entropy_weight(df, ['地块面积', '朝向得分'])

    # 评分计算
    yard_scaler = MinMaxScaler()
    yard_features = yard_scaler.fit_transform(yard_df[['院落面积', '朝向种类数']])
    yard_df['院落评分'] = (yard_weights['院落面积'] * yard_features[:, 0] +
                         yard_weights['朝向种类数'] * yard_features[:, 1])

    plot_scaler = MinMaxScaler()
    plot_features = plot_scaler.fit_transform(df[['地块面积', '朝向得分']])
    df['地块评分'] = (plot_weights['地块面积'] * plot_features[:, 0] +
                     plot_weights['朝向得分'] * plot_features[:, 1])

    # 关联院落评分
    yard_mapping = yard_df.set_index('院落ID')['院落评分'].to_dict()
    df['所属院落评分'] = df['院落ID'].map(yard_mapping)
    
    return yard_df, df, plot_weights

def get_compensation_range(current_plot_id, plot_df, plot_weights):
    """生成补偿范围报告（采用加权平均法）"""
    current = plot_df[plot_df['地块ID'] == current_plot_id].iloc[0]
    
    # 筛选候选地块（排除自身）
    candidates = plot_df[
        (plot_df['是否有住户'] == 0) &
        (plot_df['地块面积'] >= current['地块面积']) &
        (plot_df['地块面积'] <= 1.3*current['地块面积']) &
        (plot_df['朝向得分'] >= current['朝向得分']) &
        (plot_df['地块ID'] != current_plot_id)
    ]
    
    report = {
        "面积补偿范围": "无可用地块",
        "采光改善可能": False,
        "采光补偿差值": 0.0,
        "修缮补偿范围": "无需修缮",
        "可选地块数量": 0
    }
    
    if not candidates.empty:
        # ------------------- 面积补偿范围 -------------------
        min_ratio = candidates['地块面积'].min() / current['地块面积']
        max_ratio = candidates['地块面积'].max() / current['地块面积']
        report["面积补偿范围"] = f"{min_ratio:.1%} - {max_ratio:.1%}"
        
        # ------------------- 采光改善判断 -------------------
        better_orientation = candidates[candidates['朝向得分'] > current['朝向得分']]
        report["采光改善可能"] = not better_orientation.empty
        
        # ------------------- 加权平均法计算差值 -------------------
        # 当前地块综合得分
        current_score = (current['地块面积'] * plot_weights['地块面积'] + 
                        current['朝向得分'] * plot_weights['朝向得分'])
        
        # 候选地块综合得分
        candidate_scores = (
            candidates['地块面积'] * plot_weights['地块面积'] + 
            candidates['朝向得分'] * plot_weights['朝向得分']
        )
        max_score = candidate_scores.max()
        
        # 计算差值（归一化到0~1）
        score_range = max_score - current_score
        normalized_diff = score_range / (1.0 - current_score) if current_score < 1.0 else 0.0
        report["采光补偿差值"] = max(min(normalized_diff, 1.0), 0.0)
        
        # ------------------- 修缮补偿范围 -------------------
        current_total = 0.5*current['地块评分'] + 0.5*current['所属院落评分']
        candidates['综合评分'] = 0.5*candidates['地块评分'] + 0.5*candidates['所属院落评分']
        lower_scores = candidates[candidates['综合评分'] < current_total]
        
        if not lower_scores.empty:
            min_repair = (current_total - lower_scores['综合评分'].max()) * 1e5
            max_repair = (current_total - lower_scores['综合评分'].min()) * 1e5
            report["修缮补偿范围"] = f"{min(min_repair, 2e5):.0f}-{min(max_repair, 2e5):.0f}元"
        
        report["可选地块数量"] = len(candidates)
    
    return report

def find_optimal_plot(current_plot_id, plot_df):
    """查找最优迁入地块"""
    current = plot_df[plot_df['地块ID'] == current_plot_id].iloc[0]
    
    candidates = plot_df[
        (plot_df['是否有住户'] == 0) &
        (plot_df['地块面积'] >= current['地块面积']) &
        (plot_df['地块面积'] <= 1.3*current['地块面积']) &
        (plot_df['朝向得分'] >= current['朝向得分'])
    ]
    
    if not candidates.empty:
        candidates['综合评分'] = 0.5*candidates['地块评分'] + 0.5*candidates['所属院落评分']
        best = candidates.sort_values(['综合评分', '地块面积'], ascending=[False, False]).iloc[0]
        return best['地块ID']
    return None

# ------------------- 主程序 -------------------
if __name__ == "__main__":
    # 加载数据
    excel_path = r'C:\Users\kevin6366\Desktop\25mathorcup\question\B题\附件一：老城街区地块信息.xlsx'
    yard_scores, plot_scores, plot_weights = evaluate_yard_and_plots(excel_path)
    
    # 输出评分数据
    print("院落评分TOP5：")
    print(yard_scores.sort_values('院落评分', ascending=False).head(5).to_string(index=False))
    
    print("\n优质地块TOP10：")
    print(plot_scores.sort_values('地块评分', ascending=False).head(10).to_string(index=False))
    
    # 用户输入交互
    current_id = int(input("\n请输入当前居住地块ID(示例：1001): "))
    
    # 生成补偿范围报告
    report = get_compensation_range(current_id, plot_scores, plot_weights)
    
    # 输出补偿范围
    print("\n补偿范围分析：")
    print(f"面积补偿范围: {report['面积补偿范围']}")
    print(f"采光改善可能: {'是' if report['采光改善可能'] else '否'}")
    print(f"修缮补偿范围: {report['修缮补偿范围']}")
    print(f"发现{report['可选地块数量']}个候选地块")
    
    # 扩展功能：查找推荐地块
    if report['可选地块数量'] > 0:
        optimal_id = find_optimal_plot(current_id, plot_scores)
        print(f"\n推荐迁入地块: {optimal_id}（输入'Y'查看详情）")
        if input().upper() == 'Y':
            detail = plot_scores[plot_scores['地块ID'] == optimal_id].to_dict('records')[0]
            print(f"\n地块详情：")
            print(f"面积：{detail['地块面积']}㎡ 方位：{detail['地块方位']}")
            print(f"所属院落评分：{detail['所属院落评分']:.2f}")
            print(f"综合评分：{0.5*detail['地块评分']+0.5*detail['所属院落评分']:.2f}")